﻿#include "GnsClientFrame.h"
#include "MyPublicMacro.h"

GnsClientFrame*  GnsClientFrame::_pGnsClientFrame = nullptr;

GnsClientFrame::GnsClientFrame()
{
	m_bStart = false;
}

GnsClientFrame::~GnsClientFrame()
{
	stop();

	//--- 注消消息池 ----------------------------
	if (_pMsgPool != nullptr)
	{
		delete _pMsgPool;
		_pMsgPool = nullptr;
	}
}

GnsClientFrame* GnsClientFrame::getInstance()
{
	if (_pGnsClientFrame == nullptr)
	{
		_pGnsClientFrame = GnsClientFrame::create();
		assert(_pGnsClientFrame);
	}

	return _pGnsClientFrame;
}

GnsClientFrame* GnsClientFrame::create()
{
	GnsClientFrame *_pGnsClientFrame = new(std::nothrow) GnsClientFrame();
	if (_pGnsClientFrame)
	{
		//int iCount = _pGnsClientFrame->getReferenceCount();  // 获取当前的引用计数
		//_pGnsClientFrame->autorelease();	// 将对象交给自动释放池
		//_pGnsClientFrame->retain();				// 很重要，引用计数器 +1

		return _pGnsClientFrame;
	}
	else
	{
		delete _pGnsClientFrame;
		_pGnsClientFrame = nullptr;
		return nullptr;
	}
}

void GnsClientFrame::destoryInstance()
{
	if (_pGnsClientFrame != nullptr)
	{
		delete _pGnsClientFrame;
		_pGnsClientFrame = nullptr;
	}
}

bool GnsClientFrame::init()
{
	//--- 设置消息池 ----------------------------

	#if 1
		_pMsgPool = new CMemBlockPool2(_msgBlockSize, _initElementCount, _maxElementCount);
	#else
		// 极限测试用
		_pMsgPool = new CMemBlockPool2(CMemBlockPool2::DEF_MEMBLOCK_SIZE, 10, 20);		
	#endif

	assert(_pMsgPool);

	_pMsgPool->init();

	return true;
}

// 模拟框架功能的定时器
void GnsClientFrame::timerFrameFun()
{
	const int iSleepElapse = 1000;	// ms

	const int iShrink_pool_max_loop = 30;	// 多长时间收缩 CMemBlockPool2
	static int iShrink_pool_count = 0;				// CMemBlockPool2 计数器

	while (m_bStart.load())
	{
		//--- 对 CMemBlockPool2 操作 -------------------------
		if (iShrink_pool_count < iShrink_pool_max_loop)  // 还没到达指定的数量
		{
			iShrink_pool_count++;
		}
		else  // 到达指定的数量
		{
			iShrink_pool_count = 0;
			if (_pMsgPool)
			{
				_pMsgPool->use_timer_shrink_pool();
			}
		}

		std::this_thread::sleep_for(std::chrono::milliseconds(iSleepElapse));		// 毫秒级睡眠
	}
}

/* --------------------------------------------------------------------------
函数说明：
传入参数：
	iClientId					客户端 Socket 的 Id
	szServerIp				服务端 IP 地址
	iPort						服务端 端口
	iMsgBlockSize		消息块的长度，默认为 2048
	bManualConnect		1 表示手工连接，需要手工调用 ClientSocket 对象的 start 函数
										0 表示自动连接，只要 GnsClientFrame 对象的 start 一执行就自动连接啦
返回值：
	成功则返回 ClientSocket 指针，失败返回 nullptr
-------------------------------------------------------------------------- */
ClientSocket*  GnsClientFrame::registClient(int iClientId, const char* szServerIp, int iPort, int iMsgBlockSize, int bManualConnect)
{
	ClientSocket*  pClient = new(std::nothrow) ClientSocket();
	assert(pClient);

	if (pClient)
	{
		pClient->setClientInfo(iClientId, szServerIp, iPort, iMsgBlockSize, bManualConnect);
		_vecClientSocket.push_back(pClient);

		return pClient;
	}

	return nullptr;
}

// 启动
int GnsClientFrame::start()
{
	m_bStart = true;

	_frameFunThread = std::thread(&GnsClientFrame::timerFrameFun, this);

	for (auto& client : _vecClientSocket)
	{
		if (0 == client->_manualConnect)		// 0 表示自动连接，只要 GnsClientFrame 对象的 start 一执行就自动连接啦
		{			
			client->connectSocket();
		}
		else  // 1 表示手工连接，需要手工调用 ClientSocket 对象的 start 函数
		{
			// 由手动去连接......
		}
	}

	return 0;
}


/* --------------------------------------------------------------------------
函数说明：手动连接
传入参数：
	iClientId					客户端 Socket 的 Id
返回值：
	成功则返回 ClientSocket 指针，失败返回 nullptr
-------------------------------------------------------------------------- */
int  GnsClientFrame::manualConnect(int iClientId)
{
	if (iClientId >= 0 && iClientId < (int)_vecClientSocket.size())	// 数组下标合法
	{
		ClientSocket* pClientSocket = _vecClientSocket[iClientId];
		assert(pClientSocket);

		pClientSocket->connectSocket();
		return 0;
	}

	return CSH_ERR_ClientSocket_invalid;
}

/* --------------------------------------------------------------------------
函数说明：客户端 Socket 有效
传入参数：
	iClientId			客户端 Socket 的 Id
返回值：
	成功则返回 ClientSocket 指针，失败返回 nullptr
-------------------------------------------------------------------------- */
bool  GnsClientFrame::isClientSocketValid(int iClientId)
{
	if (iClientId >= 0 && iClientId < (int)_vecClientSocket.size())	// 数组下标合法
	{
		ClientSocket* pClientSocket = _vecClientSocket[iClientId];
		assert(pClientSocket);

	  return	pClientSocket->isValid();
	}

	return false;
}

/* --------------------------------------------------------------------------
函数说明：根据客户端参数类型获得客户端参数值
传入参数：
	iClientId			客户端 Socket 的 Id
	cpt  见  CLIENT_PARAM_TYPE
返回值：
	成功返回正数值，失败返回 -1
-------------------------------------------------------------------------- */
int GnsClientFrame::getParamByType(int iClientId, CLIENT_PARAM_TYPE cpt)
{
	if (iClientId >= 0 && iClientId < (int)_vecClientSocket.size())	// 数组下标合法
	{
		ClientSocket* pClientSocket = _vecClientSocket[iClientId];
		assert(pClientSocket);

		return	pClientSocket->getParamByType(cpt);
	}

	return -1;

}

// 停止
int GnsClientFrame::stop()
{
	m_bStart = false;

	if (_frameFunThread.joinable())
	{
		_frameFunThread.join();
	}

	for (auto& client : _vecClientSocket)
	{
		client->stop();
	}

	return 0;
}

int GnsClientFrame::min2(int a, int b)
{
	if (a > b)
		return b;
	else
		return a;
}

// 设置内存块的参数
void GnsClientFrame::setMemBlock(int iMsgBlockSize, int nInitElementCount, int nMaxElementCount)
{
	_msgBlockSize = iMsgBlockSize;
	_initElementCount = nInitElementCount;
	_maxElementCount = nMaxElementCount;
}

// 设置逻辑模块
void GnsClientFrame::setLogic(ILogic* pLogic)
{
	_pLogic = pLogic;		// 逻辑模块
}

// 设置数据区模块
void GnsClientFrame::setDataRepository(IDataRepository* pDataRepository)
{
	_pDataRepository = pDataRepository;			// 数据区
}

/* --------------------------------------------------------------------------
函数说明：发送数据
传入参数：
	iMainCode			主码
	iSubCode			辅助码
	pData					要发送的数据
	iDataLen				要发送的数据长度
	szFunName		调用本指令时所在函数的名称，方便查错
返回值：
	成功则返回 0，失败返回错误码
--------------------------------------------------------------------------*/
int GnsClientFrame::sendMsg(int	iClientId, int iMainCode, int iSubCode, char* pData, int iDataLen, char* szFunName)
{
	if (iClientId >= 0 && iClientId < (int)_vecClientSocket.size())	// 数组下标合法
	{
		ClientSocket* pClientSocket = _vecClientSocket[iClientId];
		assert(pClientSocket);

		pClientSocket->sendMsg(iMainCode, iSubCode, pData, iDataLen);
		return 0;
	}
	
	return CSH_ERR_ClientSocket_invalid;
}

/* --------------------------------------------------------------------------
函数说明：断开
传入参数：
	iClientId   
返回值：
	成功则返回 0，失败返回错误码
--------------------------------------------------------------------------*/
int GnsClientFrame::closeSocket(int	iClientId)
{
	if (iClientId >= 0 && iClientId < (int)_vecClientSocket.size())	// 数组下标合法
	{
		ClientSocket* pClientSocket = _vecClientSocket[iClientId];
		assert(pClientSocket);

		pClientSocket->closeSocket();
		return 0;
	}

	return CSH_ERR_ClientSocket_invalid;
}
